package com.rizzo.back.dao.impl;

import com.rizzo.back.dao.BlogEntryDao;
import com.rizzo.back.domain.BlogEntry;
import com.rizzo.back.domain.BlogUser;
import com.rizzo.back.helper.SynonymHelper;
import com.rizzo.back.util.search.SearchDataObject;
import org.apache.lucene.analysis.SimpleAnalyzer;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.queryParser.ParseException;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.highlight.Highlighter;
import org.apache.lucene.search.highlight.QueryScorer;
import org.apache.lucene.search.highlight.SimpleFragmenter;
import org.hibernate.Criteria;
import org.hibernate.criterion.Restrictions;
import org.hibernate.search.FullTextQuery;
import org.hibernate.search.FullTextSession;

import java.io.IOException;
import java.io.StringReader;
import java.util.List;

/**
 * TODO Insert JavaDoc!
 */
public class BlogEntryDaoHibernateImpl extends GenericDaoHibernateImpl<BlogEntry, Long> implements BlogEntryDao {

    private SynonymHelper synonymHelper;

    /**
     * The constructor needs the <tt>Class</tt> to be persisted. You could
     * provide this property through the Spring application context.
     */
    public BlogEntryDaoHibernateImpl() {
        super(BlogEntry.class);
    }

    /**
     * {@inheritDoc}
     */
    public List<BlogEntry> getSearchBlogEntriesForBlogUser(SearchDataObject searchDataObject, BlogUser blogUser) throws ClassNotFoundException, ParseException, InstantiationException, IllegalAccessException, IOException {
        FullTextSession fullTextSession = getSearchSession();
        Criteria blogEntryCriteria = getSearchSession().createCriteria(BlogEntry.class);
        Criteria blogUserCriteria = blogEntryCriteria.createCriteria("blogUser");
        blogUserCriteria.add(Restrictions.eq("id", blogUser.getId()));
        Query query;
        if (searchDataObject.isSynonymSearch()) {
            query = this.synonymHelper.expandQuery(searchDataObject, fullTextSession,
                    searchDataObject.getSynonymAnalyzer().getInstantiation(), searchDataObject.getSynonymBoost());
        } else {
            query = searchDataObject.getCombinedQuery();
        }
        FullTextQuery fullTextQuery = fullTextSession.createFullTextQuery(query, BlogEntry.class).setCriteriaQuery(blogEntryCriteria);
        List<BlogEntry> blogEntries = fullTextQuery.list();
        if (searchDataObject.isHighlighted()) {
            Highlighter highlighter = new Highlighter(new QueryScorer(query));
            highlighter.setTextFragmenter(new SimpleFragmenter(searchDataObject.getHighlightFragmentLength()));
            for (BlogEntry blogEntry : blogEntries) {
                SimpleAnalyzer simpleAnalyzer = new SimpleAnalyzer();
                for (String field : searchDataObject.getFields()) {
                    String fieldText = blogEntry.getContent();
                    TokenStream tokenStream = simpleAnalyzer.tokenStream(field, new StringReader(fieldText));
                    String result = highlighter.getBestFragments(tokenStream, fieldText, searchDataObject.getMaxNumberOfHighlightFragments(), " ...");
                    blogEntry.setContent(result);
                }
            }
        }
        return blogEntries;
    }

    public void setSynonymHelper(SynonymHelper synonymHelper) {
        this.synonymHelper = synonymHelper;
    }
}